using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace EuropeEngulfed.NET
{
    class StrategicMove : Move
    {
        private MapInfo.RegionID regionMovedFrom;
        private MapInfo.RegionID regionMovedTo;
        private PlayingPiece pieceMoved;
        private int numStepLossesFromNavalInterdiction;
        private List<MapInfo.RegionID> seaRegionsPassedThrough;
        private IGameStateInfoProvider gameInfoProvider;
        private bool aroundTheCape = false;
        protected bool breakThroughMove = false;
        private bool goesThroughWesternWeatherZone = false;
        private bool findRouteWithoutGoingThroughWesternWeatherZone = false;
        private bool moveBlockedByOperationOverlord = false;
        private int numSeaRegionsAllowed = 0;

        public StrategicMove(GameTurn.GameDate gameDate, GameTurn.GamePhase gamePhase, GameTurn.GameSubPhase gameSubPhase, MapInfo.RegionID regionMovedFrom, MapInfo.RegionID regionMovedTo, PlayingPiece pieceMoved)
            : base(gameDate, gamePhase, gameSubPhase)
        {
            this.regionMovedFrom = regionMovedFrom;
            this.regionMovedTo = regionMovedTo;
            this.pieceMoved = pieceMoved;
            seaRegionsPassedThrough = new List<MapInfo.RegionID>();
        }

        private bool moveBlockedByBreakthroughWeather(MapInfo.RegionID region, IGameStateInfoProvider gameInfoProvider)
        {
            if (this.breakThroughMove)
            {
                GameState.Weather regionWeather = GameState.Weather.Clear;
                LandRegion landRegion = (LandRegion)MapInfo.GetRegion(region);
                switch (landRegion.WeatherZone)
                {
                    case MapInfo.weatherZone.easternZone:
                        regionWeather = gameInfoProvider.GetCurrentEasternWeather();
                        break;
                    case MapInfo.weatherZone.southernZone:
                        regionWeather = gameInfoProvider.GetCurrentSouthernWeather();
                        break;
                    case MapInfo.weatherZone.westernZone:
                        regionWeather = gameInfoProvider.GetCurrentWesternWeather();
                        break;
                }

                return (regionWeather == GameState.Weather.Mud || regionWeather == GameState.Weather.LightMud);
            }

            return false;
        }

        public bool BreakThroughMove
        {
            get
            {
                return breakThroughMove;
            }

            set
            {
                breakThroughMove = value;
            }
        }

        public bool AroundTheCape
        {
            get
            {
                return aroundTheCape;
            }

            set
            {
                aroundTheCape = value; 
            }
        }

        public List<MapInfo.RegionID> SeaRegions
        {
            get
            {
                return seaRegionsPassedThrough;
            }

            set
            {
                seaRegionsPassedThrough = value;
            }
        }

        public MapInfo.CountryID Country
        {
            get
            {
                return pieceMoved.CountryOwner;
            }
        }

        public MapInfo.RegionID FromRegion
        {
            get
            {
                return regionMovedFrom;
            }
        }

        public MapInfo.RegionID ToRegion
        {
            get
            {
                return regionMovedTo;
            }
        }

        public PlayingPiece Piece
        {
            get
            {
                return pieceMoved;
            }
        }

        public int NavalInterdictionLosses
        {
            get
            {
                return numStepLossesFromNavalInterdiction;
            }
        }

        public bool GoesThroughWesternWeatherZone
        {
            get
            {
                return goesThroughWesternWeatherZone;
            }
        }

        public void AddSeaRegionToPassThrough(MapInfo.RegionID seaRegion)
        {
            this.seaRegionsPassedThrough.Add(seaRegion);
        }

        protected override void ProcessMove(GameState gameState)
        {
            LandRegionState landRegionMovedFrom = (LandRegionState)gameState.GetRegionState(this.regionMovedFrom);
            LandRegionState landRegionMovedTo = (LandRegionState)gameState.GetRegionState(this.regionMovedTo);

            if (this.pieceMoved is Block)
            {
                Block blockMoved = (Block)this.pieceMoved;
                Block blockToMove = landRegionMovedFrom.RemoveBlock(blockMoved.CountryOwner, blockMoved.getBlockType(), (int)blockMoved.CurrentStrength, (int)blockMoved.MaxStrength, blockMoved.OutOfSupply);
                if (this.numStepLossesFromNavalInterdiction >= blockToMove.CurrentStrength)
                    gameState.ReturnPlayingPieceToForcePool(blockToMove);
                else
                {
                    blockToMove.CurrentStrength -= (uint)this.numStepLossesFromNavalInterdiction;
                    landRegionMovedTo.AddBlock(blockToMove);
                }
            }
            else if (this.pieceMoved is GroundSupportUnit)
            {
                GroundSupportUnit GSUMoved = (GroundSupportUnit)this.pieceMoved;
                GroundSupportUnit GSUToMove = landRegionMovedFrom.RemoveGSU(GSUMoved.CountryOwner, GSUMoved.OutOfSupply);
                if (this.numStepLossesFromNavalInterdiction <= 0)
                    landRegionMovedTo.AddGSU(GSUToMove);
                else
                    gameState.ReturnPlayingPieceToForcePool(GSUToMove);
            }

            if(gameState.IsAxisCountry(pieceMoved.CountryOwner))
            {
                if (pieceMoved.CountryOwner == MapInfo.CountryID.Italy)
                    gameState.SpendStratMoveForCountry(MapInfo.CountryID.Italy);
                else
                    gameState.SpendStratMoveForCountry(MapInfo.CountryID.Germany);
            }
            else
            {
                if(aroundTheCape)
                {
                    int numBritishMovesLeft = gameState.GetNumStratMovesForCountry(MapInfo.CountryID.GreatBritain);
                    for (int i = 0; i < numBritishMovesLeft; i++)
                    {
                        gameState.SpendStratMoveForCountry(MapInfo.CountryID.GreatBritain);
                    }
                }
                else
                {
                    switch (pieceMoved.CountryOwner)
                    {
                        case MapInfo.CountryID.GreatBritain:
                            gameState.SpendStratMoveForCountry(MapInfo.CountryID.GreatBritain);
                            break;
                        case MapInfo.CountryID.France:
                            gameState.SpendStratMoveForCountry(MapInfo.CountryID.France);
                            break;
                        case MapInfo.CountryID.USA:
                            gameState.SpendStratMoveForCountry(MapInfo.CountryID.USA);
                            break;
                        case MapInfo.CountryID.USSR:
                            gameState.SpendStratMoveForCountry(MapInfo.CountryID.USSR);
                            break;
                        default:
                            gameState.SpendStratMoveForCountry(MapInfo.CountryID.GreatBritain);
                            break;
                    }
                }
            }

            if(aroundTheCape)
            {
                SeaRegionState seaRegionState = (SeaRegionState)gameState.GetRegionState(MapInfo.RegionID.AtlanticOcean);
                seaRegionState.FlipCountryFleetsToWithoutTransports(4, MapInfo.CountryID.GreatBritain);
            }
            else
            {
                foreach (MapInfo.RegionID seaRegionPassedThrough in seaRegionsPassedThrough)
                {
                    if (seaRegionPassedThrough == MapInfo.RegionID.MediteraneanSea && this.pieceMoved.CountryOwner == MapInfo.CountryID.Germany)
                        gameState.GermanUnitHasUsedItalianSeaTransport = true;

                    SeaRegionState seaRegionState = (SeaRegionState)gameState.GetRegionState(seaRegionPassedThrough);
                    if (gameState.IsAlliedCountry(this.pieceMoved.CountryOwner))
                    {
                        if (pieceMoved.CountryOwner == MapInfo.CountryID.France)
                            seaRegionState.FlipCountryFleetsToWithoutTransports(1, MapInfo.CountryID.France);
                        else
                            seaRegionState.FlipCountryFleetsToWithoutTransports(1, MapInfo.CountryID.GreatBritain);
                    }
                    else
                        seaRegionState.FlipAxisFleetsToWithoutTransports(1);
                }
            }

            /*The Vichy unit is removed from the map without resisting
            if the Germans perform this occupation, and as of that moment,
            the Axis Player controls Lebanon (and Syria, if it too was Vichycontrolled).*/
            if(this.pieceMoved.CountryOwner == MapInfo.CountryID.Germany)
            {
                if (this.regionMovedTo == MapInfo.RegionID.Lebanon && !gameState.IsNationAtWar(MapInfo.CountryID.VichyFrance) && gameState.GetRegionCountryControl(this.regionMovedTo) == MapInfo.CountryID.VichyFrance)
                {
                    LandRegionState lebanonRegionState = (LandRegionState)gameState.GetRegionState(MapInfo.RegionID.Lebanon);
                    LandRegionState syriaRegionState = (LandRegionState)gameState.GetRegionState(MapInfo.RegionID.Syria);

                    if (lebanonRegionState.CountryControl == MapInfo.CountryID.VichyFrance)
                        lebanonRegionState.CountryControl = MapInfo.CountryID.Germany;
                    if (syriaRegionState.CountryControl == MapInfo.CountryID.VichyFrance)
                        syriaRegionState.CountryControl = MapInfo.CountryID.Germany;

                    for (int i = 0; lebanonRegionState.GetBlockAt(i) != null; i++)
                    {
                        Block block = lebanonRegionState.GetBlockAt(i);
                        if (block.CountryOwner == MapInfo.CountryID.VichyFrance)
                        {
                            lebanonRegionState.ReturnPlayingPieceToForcePool(gameState, block);
                            break;
                        }
                    }

                    for (int i = 0; syriaRegionState.GetBlockAt(i) != null; i++)
                    {
                        Block block = syriaRegionState.GetBlockAt(i);
                        if (block.CountryOwner == MapInfo.CountryID.VichyFrance)
                        {
                            syriaRegionState.ReturnPlayingPieceToForcePool(gameState, block);
                            break;
                        }
                    }
                }
            }
        }

        public bool IsLegalWithoutConsideringRoute(IGameStateInfoProvider gameStateInfoProvider, ref string ruleString)
        {
            if (!MapInfo.IsLandRegion(this.regionMovedTo))
            {
                ruleString = "Units cannot be moved to a sea region";
                return false;
            }

            if (gameStateInfoProvider.GetRegionsAxisBlockList(this.regionMovedFrom).Count > 0 && gameStateInfoProvider.GetRegionsAlliedBlockList(this.regionMovedFrom).Count > 0)
            {
                ruleString = "Only units located in uncontested areas can strat move, see 5.2 Strategic Movement Phases (Strat-Moves)";
                return false;
            }

            bool targetRegionIsFriendly = gameStateInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) ? gameStateInfoProvider.IsAxisCountry(gameStateInfoProvider.GetRegionControl(this.regionMovedTo)) : gameStateInfoProvider.IsAlliedCountry(gameStateInfoProvider.GetRegionControl(this.regionMovedTo));
            bool targetRegionIsContested = gameStateInfoProvider.GetRegionsAxisBlockList(this.regionMovedTo).Count > 0 && gameStateInfoProvider.GetRegionsAlliedBlockList(this.regionMovedTo).Count > 0;
            if (!targetRegionIsFriendly)
            {
                ruleString = "Strat moves can only be made to friendly controlled areas, see 5.2 Strategic Movement Phases (Strat-Moves)";
                return false;
            }

            if (targetRegionIsContested)
            {
                ruleString = "Strat moves can only be made to uncontested areas, see 5.2 Strategic Movement Phases (Strat-Moves)";
                return false;
            }

            if (pieceMoved.OutOfSupply)
            {
                ruleString = "Out of supply units may not strat move, see 3.4 Effects of Being Out of Supply (OOS)";
                return false;
            }

            return true;
        }

        private bool AxisPlayerCanTranferFleetPoints(MapInfo.RegionID from, MapInfo.RegionID to)
        {//8.32 AXIS FLEET POINT TRANSFER
            if ((from == MapInfo.RegionID.BalticSea && to == MapInfo.RegionID.AtlanticOcean)
            || (from == MapInfo.RegionID.AtlanticOcean && to == MapInfo.RegionID.BalticSea))
            {//8.321 Axis transfer between the Baltic and Atlantic
                if (gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Rhur)) || gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Denmark)))
                    return true;
            }
            else if ((from == MapInfo.RegionID.AtlanticOcean && to == MapInfo.RegionID.MediteraneanSea)
                || (from == MapInfo.RegionID.MediteraneanSea && to == MapInfo.RegionID.AtlanticOcean))
            {//8.322 Axis transfer from the Atlantic to the Mediterranean
                if (!gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Gibraltar)) || !gameInfoProvider.IsNationAtWar(MapInfo.CountryID.Italy))
                    return false;
                if (from == MapInfo.RegionID.MediteraneanSea && to == MapInfo.RegionID.AtlanticOcean)
                {
                    if (!gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Alexandria)) && !gameInfoProvider.IsNationAtWar(MapInfo.CountryID.USSR))
                        return false;
                }
                return true;
            }
            return false;
        }

        private bool AlliedPlayerCanTranferFleetPoints(MapInfo.RegionID from, MapInfo.RegionID to)
        {
            if(from == MapInfo.RegionID.AtlanticOcean && to == MapInfo.RegionID.MediteraneanSea
                || to == MapInfo.RegionID.AtlanticOcean && from == MapInfo.RegionID.MediteraneanSea)
            {
                if (gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Gibraltar)))
                    return true;
                else if (gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Alexandria)) && gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Sinai)))
                    return true;
            }
            return false;
        }

        public bool IsValidMapConnection(Edge<Region, Adjacency> edge, Region start, List<Region> currentPath)
        {
            string ruleString = "";
            if(edge.Data is LandToLandAdjacency)
            {
                if(findRouteWithoutGoingThroughWesternWeatherZone)
                {
                    LandRegion landRegionStart = (LandRegion)MapInfo.GetRegion(edge.Start.RegionID);
                    LandRegion landRegionEnd = (LandRegion)MapInfo.GetRegion(edge.End.RegionID);
                    if (landRegionStart.WeatherZone == MapInfo.weatherZone.westernZone || landRegionEnd.WeatherZone == MapInfo.weatherZone.westernZone)
                        return false;
                }
                
                if(((LandToLandAdjacency)edge.Data).ConnectionType == LandToLandAdjacency.LandConnectionType.AirConnection)
                {
                    if (!(this.pieceMoved is GroundSupportUnit))
                        return false;
                }

                MapInfo.RegionID endRegion = edge.Start.RegionID == start.RegionID ? edge.End.RegionID : edge.Start.RegionID;
                if (!Move.IsWithinOperationLimits(this.gameInfoProvider, start.RegionID, endRegion, this.pieceMoved, true, ref ruleString))
                    return false;
                if (moveBlockedByBreakthroughWeather(edge.Start.RegionID, this.gameInfoProvider))
                    return false;
                if (moveBlockedByBreakthroughWeather(edge.End.RegionID, this.gameInfoProvider))
                    return false;
            }
            else if(edge.Data is SeaLandAdjacency)
            {
                if(start.IsLandRegion()) //moving to  a sea region
                {
                    int currentNumberOfSeaRegionsTraversed = 0;
                    foreach(Region regionTraversed in currentPath)
                    {
                        if (regionTraversed.IsSeaRegion())
                            currentNumberOfSeaRegionsTraversed++;
                    }

                    if (currentNumberOfSeaRegionsTraversed >= this.numSeaRegionsAllowed)
                        return false;
                }

                MapInfo.RegionID landRegionID = MapInfo.IsSeaRegion(edge.Start.RegionID) ? edge.End.RegionID : edge.Start.RegionID;
                List<FleetPoint> fleetPointsAvailable;

                if(findRouteWithoutGoingThroughWesternWeatherZone)
                {
                    LandRegion landRegion = (LandRegion)MapInfo.GetRegion(landRegionID);
                    if (landRegion.WeatherZone == MapInfo.weatherZone.westernZone)
                        return false;
                }

                if (moveBlockedByBreakthroughWeather(landRegionID, this.gameInfoProvider))
                    return false;

                if (gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner))
                {
                    MapInfo.RegionID seaRegionID = MapInfo.IsSeaRegion(edge.Start.RegionID) ? edge.Start.RegionID : edge.End.RegionID;

                    /*Axis units may trace supply and Strat-move through Vichy
                    French territory (Sea Supply and Strat-moves through Vichy-controlled
                    Ports may only be traced through the Mediterranean).*/
                    if (gameInfoProvider.GetRegionControl(landRegionID) == MapInfo.CountryID.VichyFrance && seaRegionID != MapInfo.RegionID.MediteraneanSea)
                        return false;
                }

                if(!((SeaLandAdjacency)edge.Data).Port)
                {
                    if (((SeaLandAdjacency)edge.Data).LandingBeach > 0)
                    {
                        if (!this.gameInfoProvider.RegionContainsABeachHead(landRegionID))
                            return false;
                    }
                    else
                        return false;
                }

                if(gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) || this.pieceMoved.CountryOwner == MapInfo.CountryID.Italy)
                {
                    MapInfo.RegionID seaRegionID = MapInfo.IsSeaRegion(edge.Start.RegionID) ? edge.Start.RegionID : edge.End.RegionID;
                    if(seaRegionID == MapInfo.RegionID.MediteraneanSea)
                        fleetPointsAvailable = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Italy, seaRegionID);
                    else
                        fleetPointsAvailable = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, seaRegionID);
                }
                else
                {
                    MapInfo.RegionID seaRegionID = MapInfo.IsSeaRegion(edge.Start.RegionID) ? edge.Start.RegionID : edge.End.RegionID;
                    if (seaRegionID == MapInfo.RegionID.MediteraneanSea || seaRegionID == MapInfo.RegionID.AtlanticOcean || seaRegionID == MapInfo.RegionID.RedSea)
                    {
                        if (this.pieceMoved.CountryOwner == MapInfo.CountryID.France)
                            fleetPointsAvailable = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, seaRegionID);
                        else
                            fleetPointsAvailable = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, seaRegionID);
                    }
                    else
                    {
                        fleetPointsAvailable = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.USSR, seaRegionID);
                    }
                }

                bool foundAvailableTransport = false;
                foreach(FleetPoint fleet in fleetPointsAvailable)
                {
                    if (!fleet.WithoutTransport)
                    {
                        foundAvailableTransport = true;
                        break;
                    }
                }

                if (!foundAvailableTransport)
                    return false;
            }
            else if(edge.Data is SeaSeaAdjacency)
            {
                List<FleetPoint> fleetPointsAvailableInRegion1;
                List<FleetPoint> fleetPointsAvailableInRegion2;
                if(gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) || this.pieceMoved.CountryOwner == MapInfo.CountryID.Italy)
                {
                    if (!AxisPlayerCanTranferFleetPoints(start.RegionID, edge.End.RegionID != start.RegionID ? edge.End.RegionID : edge.Start.RegionID))
                        return false;
                }
                else
                {
                    if (!AlliedPlayerCanTranferFleetPoints(start.RegionID, edge.End.RegionID != start.RegionID ? edge.End.RegionID : edge.Start.RegionID))
                        return false;
                }

                if (gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) || this.pieceMoved.CountryOwner == MapInfo.CountryID.Italy)
                {
                    if (edge.Start.RegionID == MapInfo.RegionID.MediteraneanSea)
                        fleetPointsAvailableInRegion1 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Italy, edge.Start.RegionID);
                    else
                        fleetPointsAvailableInRegion1 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, edge.Start.RegionID);

                    if (edge.End.RegionID == MapInfo.RegionID.MediteraneanSea)
                        fleetPointsAvailableInRegion2 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Italy, edge.End.RegionID);
                    else
                        fleetPointsAvailableInRegion2 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, edge.End.RegionID);
                }
                else
                {
                    if (edge.Start.RegionID == MapInfo.RegionID.MediteraneanSea || edge.Start.RegionID == MapInfo.RegionID.AtlanticOcean)
                    {
                        if (this.pieceMoved.CountryOwner == MapInfo.CountryID.France)
                            fleetPointsAvailableInRegion1 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, edge.Start.RegionID);
                        else
                            fleetPointsAvailableInRegion1 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, edge.Start.RegionID);
                    }
                    else
                    {
                        fleetPointsAvailableInRegion1 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.USSR, edge.Start.RegionID);
                    }

                    if (edge.End.RegionID == MapInfo.RegionID.MediteraneanSea || edge.End.RegionID == MapInfo.RegionID.AtlanticOcean)
                    {
                        if (this.pieceMoved.CountryOwner == MapInfo.CountryID.France)
                            fleetPointsAvailableInRegion2 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, edge.End.RegionID);
                        else
                            fleetPointsAvailableInRegion2 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, edge.End.RegionID);
                    }
                    else
                    {
                        fleetPointsAvailableInRegion2 = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.USSR, edge.End.RegionID);
                    }
                }

                bool foundAvailableTransport = false;
                foreach (FleetPoint fleet in fleetPointsAvailableInRegion1)
                {
                    if (!fleet.WithoutTransport)
                    {
                        foundAvailableTransport = true;
                        break;
                    }
                }

                if (!foundAvailableTransport)
                    return false;

                foundAvailableTransport = false;
                foreach (FleetPoint fleet in fleetPointsAvailableInRegion2)
                {
                    if (!fleet.WithoutTransport)
                    {
                        foundAvailableTransport = true;
                        break;
                    }
                }

                if (!foundAvailableTransport)
                    return false;
            }

            if(gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) || this.pieceMoved.CountryOwner == MapInfo.CountryID.Italy)
            {
                if(MapInfo.IsLandRegion(edge.Start.RegionID))
                {
                    if (gameInfoProvider.GetRegionsAlliedBlockList(edge.Start.RegionID).Count > 0)
                        return false;
                    if (!gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(edge.Start.RegionID)) || !gameInfoProvider.IsNationAtWar(gameInfoProvider.GetRegionControl(edge.Start.RegionID)))
                    {
                        if (this.pieceMoved.CountryOwner != MapInfo.CountryID.Italy || !(gameInfoProvider.GetRegionControl(edge.Start.RegionID) == MapInfo.CountryID.Italy))
                        {
                            if (gameInfoProvider.GetRegionControl(edge.Start.RegionID) != MapInfo.CountryID.VichyFrance)
                                return false;
                        }
                    }
                }

                if(MapInfo.IsLandRegion(edge.End.RegionID))
                {
                    if (gameInfoProvider.GetRegionsAlliedBlockList(edge.End.RegionID).Count > 0)
                        return false;
                    if (!gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(edge.End.RegionID)) || !gameInfoProvider.IsNationAtWar(gameInfoProvider.GetRegionControl(edge.End.RegionID)))
                    {
                        if (this.pieceMoved.CountryOwner != MapInfo.CountryID.Italy || !(gameInfoProvider.GetRegionControl(edge.End.RegionID) == MapInfo.CountryID.Italy))
                        {
                            if (gameInfoProvider.GetRegionControl(edge.End.RegionID) != MapInfo.CountryID.VichyFrance)
                                return false;
                        }
                    }
                }
            }
            else
            {
                if (MapInfo.IsLandRegion(edge.Start.RegionID))
                {
                    if (gameInfoProvider.GetRegionsAxisBlockList(edge.Start.RegionID).Count > 0)
                        return false;
                    if (!gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(edge.Start.RegionID)) || !gameInfoProvider.IsNationAtWar(gameInfoProvider.GetRegionControl(edge.Start.RegionID)))
                    {
                        if (this.pieceMoved.CountryOwner != MapInfo.CountryID.USSR || !(gameInfoProvider.GetRegionControl(edge.Start.RegionID) == MapInfo.CountryID.USSR))
                            return false;
                    }

                    if (this.pieceMoved.CountryOwner != MapInfo.CountryID.USSR && gameInfoProvider.GetRegionControl(edge.Start.RegionID) == MapInfo.CountryID.USSR)
                        return false;
                }

                if (MapInfo.IsLandRegion(edge.End.RegionID))
                {
                    if (gameInfoProvider.GetRegionsAxisBlockList(edge.End.RegionID).Count > 0)
                        return false;
                    if (!gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(edge.End.RegionID)) || !gameInfoProvider.IsNationAtWar(gameInfoProvider.GetRegionControl(edge.End.RegionID)))
                    {
                        if (this.pieceMoved.CountryOwner != MapInfo.CountryID.USSR || !(gameInfoProvider.GetRegionControl(edge.End.RegionID) == MapInfo.CountryID.USSR))
                            return false;
                    }

                    if (this.pieceMoved.CountryOwner != MapInfo.CountryID.USSR && gameInfoProvider.GetRegionControl(edge.End.RegionID) == MapInfo.CountryID.USSR)
                        return false;
                }
            }

            if(this.pieceMoved is Block)
            {
                if(((Block)this.pieceMoved).getBlockType() == Block.BlockType.armor || ((Block)this.pieceMoved).getBlockType() == Block.BlockType.eliteArmor)
                {
                    if (MapInfo.IsLandRegion(edge.Start.RegionID))
                    {
                        if (((LandRegion)edge.Start).Terrain == MapInfo.terrainType.swamp)
                            return false;
                    }

                    if (MapInfo.IsLandRegion(edge.End.RegionID))
                    {
                        if (((LandRegion)edge.End).Terrain == MapInfo.terrainType.swamp)
                            return false;
                    }
                }
            }

            return true;
        }

        private int GetNumSeaTransportsNeeded(List<MapInfo.RegionID> path)
        {
            int rtv = 0;
            if(gameInfoProvider.IsAlliedCountry(this.pieceMoved.CountryOwner))
            {
                foreach (MapInfo.RegionID regionIDInPath in path)
                {
                    if (MapInfo.IsSeaRegion(regionIDInPath))
                    {
                        rtv++;
                    }
                }
            }
            else
            {
                foreach (MapInfo.RegionID regionIDInPath in path)
                {
                    if (MapInfo.IsSeaRegion(regionIDInPath))
                        rtv++;
                }
            }

            return rtv;
        }

        public bool IsEquivalentStratPath(List<Region> completePath, List<Region> partialPath)
        {
            List<Region> listOfSeaRegions1 = new List<Region>();
            List<Region> listOfSeaRegions2 = new List<Region>();

            foreach (Region region in completePath)
            {
                if(region.IsSeaRegion())
                {
                    listOfSeaRegions1.Add(region);
                }
            }

            foreach (Region region in partialPath)
            {
                if (region.IsSeaRegion())
                {
                    listOfSeaRegions2.Add(region);
                }
            }

            if (listOfSeaRegions1.Count == listOfSeaRegions2.Count)
            {
                foreach(Region region in listOfSeaRegions1)
                {
                    if (!listOfSeaRegions2.Contains(region))
                        return false;
                }

                /*if (completePath.Contains(partialPath[partialPath.Count - 1]))
                    return true;*/
                if (completePath[completePath.Count - 1].RegionID == partialPath[partialPath.Count - 1].RegionID)
                    return true;
            }

            return false;
        }

        public bool IsEndStratPathSearch(List<List<Region>> pathsToCheck)
        {
            foreach(List<Region> path in pathsToCheck)
            {
                int numSeaRegions = 0;
                bool foundTargetRegion = false;
                foreach(Region region in path)
                {
                    if (region.IsSeaRegion())
                    {
                        numSeaRegions++;
                    }

                    if(region.RegionID == this.regionMovedTo)
                    {
                        foundTargetRegion = true;
                    }
                }

                if (numSeaRegions <= this.numSeaRegionsAllowed && foundTargetRegion)
                    return true;
            }

            return false;
        }

        public bool FindRoute(List<List<MapInfo.RegionID>> listOfSeaRegionsNeededToPassThrough, IGameStateInfoProvider gameStateInfoProvider, bool findMoveWithoutGoingThroughWesternWeatherZone, bool moveBlockedByOverlord)
        {
            bool lookForAnotherRoute = true;
            LandRegion landRegionFrom = (LandRegion)MapInfo.GetRegion(this.regionMovedFrom);
            LandRegion landRegionTo = (LandRegion)MapInfo.GetRegion(this.regionMovedTo);
            this.findRouteWithoutGoingThroughWesternWeatherZone = findMoveWithoutGoingThroughWesternWeatherZone || moveBlockedByOverlord;
            this.moveBlockedByOperationOverlord = moveBlockedByOverlord;
            List<List<Region>> paths = null;
            string rule = "";

            if (!Move.IsWithinOperationLimits(gameStateInfoProvider, this.regionMovedFrom, this.regionMovedTo, this.pieceMoved, ref rule))
                return false;

            if (moveBlockedByBreakthroughWeather(this.regionMovedFrom, this.gameInfoProvider))
                return false;
            if (moveBlockedByBreakthroughWeather(this.regionMovedTo, this.gameInfoProvider))
                return false;

            List<List<MapInfo.RegionID>> tempListOfSeaRegionsNeededToPassThrough = new List<List<MapInfo.RegionID>>();
            gameInfoProvider = gameStateInfoProvider;
            if(findRouteWithoutGoingThroughWesternWeatherZone)
            {
                if(landRegionFrom.WeatherZone != MapInfo.weatherZone.westernZone && landRegionTo.WeatherZone != MapInfo.weatherZone.westernZone)
                {
                    this.numSeaRegionsAllowed = 0;
                    paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                    if(paths == null)
                    {
                        this.numSeaRegionsAllowed++;
                        paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                    }

                    if (paths == null)
                    {
                        this.numSeaRegionsAllowed++;
                        paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                    }
                }

                if(paths == null)
                {
                    if (moveBlockedByOperationOverlord)
                        return false;
                    else
                        this.goesThroughWesternWeatherZone = true;
                    lookForAnotherRoute = true;
                    this.findRouteWithoutGoingThroughWesternWeatherZone = false;
                }
                else
                {
                    lookForAnotherRoute = false;
                }
            }

            if (lookForAnotherRoute)
            {
                this.numSeaRegionsAllowed = 0;
                paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                if (paths == null)
                {
                    this.numSeaRegionsAllowed++;
                    paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                }

                if (paths == null)
                {
                    this.numSeaRegionsAllowed++;
                    paths = MapInfo.GetPaths(this.regionMovedFrom, this.regionMovedTo, IsValidMapConnection, IsEquivalentStratPath, IsEndStratPathSearch);
                }
            }

            listOfSeaRegionsNeededToPassThrough.Clear();

            if (paths == null)
                return false;
            else
            {
                if (paths.Count == 0)
                    return false;
                else
                {
                    int minimumSeaRegions = 4;
                    foreach (List<Region> path in paths)
                    {
                        List<MapInfo.RegionID> seaRegionsPassedThrough = new List<MapInfo.RegionID>();
                        foreach (Region regionInPath in path)
                        {
                            if (MapInfo.IsSeaRegion(regionInPath.RegionID))
                                seaRegionsPassedThrough.Add(regionInPath.RegionID);
                        }

                        if (seaRegionsPassedThrough.Count == 0)
                        {
                            listOfSeaRegionsNeededToPassThrough.Clear();
                            return true; //found a land only path so we can just return
                        }
                        else
                        {
                            if (GetNumSeaTransportsNeeded(seaRegionsPassedThrough) < minimumSeaRegions)
                                minimumSeaRegions = seaRegionsPassedThrough.Count;
                            tempListOfSeaRegionsNeededToPassThrough.Add(seaRegionsPassedThrough);
                        }
                    }

                    foreach (List<MapInfo.RegionID> seaRegionIDs in tempListOfSeaRegionsNeededToPassThrough)
                    {
                        bool foundIdenticalListOfSeaRegions = false;

                        foreach (List<MapInfo.RegionID> seaRegionIDListToCheck in listOfSeaRegionsNeededToPassThrough)
                        {
                            bool foundDifferentRegion = false;
                            foreach (MapInfo.RegionID seaRegionIDToCheck in seaRegionIDListToCheck)
                            {
                                if (!seaRegionIDs.Contains(seaRegionIDToCheck))
                                {
                                    foundDifferentRegion = true;
                                    break;
                                }
                            }

                            if (!foundDifferentRegion)
                            {
                                foundIdenticalListOfSeaRegions = true;
                                break;
                            }
                        }

                        if (!foundIdenticalListOfSeaRegions)
                        {
                            if (GetNumSeaTransportsNeeded(seaRegionsPassedThrough) <= minimumSeaRegions)
                                listOfSeaRegionsNeededToPassThrough.Add(seaRegionIDs);
                        }
                    }
                }
            }
            return true;
        }

        public bool DoNavalInterdiction(IGameStateInfoProvider gameInfoProvider, Random r)
        {
            bool interceptionOccured = false;
            int numHits = 0;
            if(gameInfoProvider.IsNationAtWar(this.pieceMoved.CountryOwner))
            {
                bool axisMove = gameInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner);
                foreach (MapInfo.RegionID seaRegionID in seaRegionsPassedThrough)
                {
                    int numEnemyFleets = 0;
                    int numFriendlyFleets = 0;
                    switch(seaRegionID)
                    {
                        case MapInfo.RegionID.BalticSea:
                            if(axisMove)
                            {
                                if (gameInfoProvider.IsNationAtWar(MapInfo.CountryID.USSR))
                                    numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.USSR, MapInfo.RegionID.BalticSea).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, MapInfo.RegionID.BalticSea).Count;
                            }
                            else
                            {
                                numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, MapInfo.RegionID.BalticSea).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.USSR, MapInfo.RegionID.BalticSea).Count;
                            }
                            break;
                        case MapInfo.RegionID.AtlanticOcean:
                            if (axisMove)
                            {
                                numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, MapInfo.RegionID.AtlanticOcean).Count + gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, MapInfo.RegionID.AtlanticOcean).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, MapInfo.RegionID.AtlanticOcean).Count;
                            }
                            else
                            {
                                numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Germany, MapInfo.RegionID.AtlanticOcean).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, MapInfo.RegionID.AtlanticOcean).Count + gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, MapInfo.RegionID.AtlanticOcean).Count;
                            }
                            break;
                        case MapInfo.RegionID.MediteraneanSea:
                            if(axisMove)
                            {
                                if(gameInfoProvider.IsNationAtWar(MapInfo.CountryID.Italy))
                                    numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, MapInfo.RegionID.MediteraneanSea).Count + gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, MapInfo.RegionID.MediteraneanSea).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Italy, MapInfo.RegionID.MediteraneanSea).Count;
                            }
                            else
                            {
                                //9.45 COLLAPSE OF ITALIAN MORALE: ...b) Italian Fleet Points may not initiate Naval Combat or Naval Interdiction for the rest of the game.
                                if (gameInfoProvider.IsNationAtWar(MapInfo.CountryID.Italy) && !gameInfoProvider.ItalianMoraleHasCollapsed())
                                    numEnemyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.Italy, MapInfo.RegionID.MediteraneanSea).Count;
                                numFriendlyFleets = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, MapInfo.RegionID.MediteraneanSea).Count + gameInfoProvider.GetFleetPointList(MapInfo.CountryID.France, MapInfo.RegionID.MediteraneanSea).Count;
                            }
                            break;
                    }

                    /*8.22 In order to interdict, a player must have at least one Fleet Point in
                    the Sea-zone for every two Fleet Points the enemy has in that same
                    zone.*/
                    if(numEnemyFleets >= numFriendlyFleets / 2 && numEnemyFleets > 0)
                    {
                        bool hittingOn56 = axisMove ? gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Sicily)) || gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Malta)) : gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Sicily)) || gameInfoProvider.IsAxisCountry(gameInfoProvider.GetRegionControl(MapInfo.RegionID.Malta));

                        for(int i = 0; i < numEnemyFleets; i++)
                        {
                            uint dieRoll = (uint)(r.Next(6) + 1);
                            if (dieRoll == 6)
                                numHits++;
                            else if (dieRoll == 5 && hittingOn56)
                                numHits++;
                        }

                        interceptionOccured = true;
                    }
                }
            }

            if(this.pieceMoved is GroundSupportUnit)
            {
                if (numHits > 0)
                    this.numStepLossesFromNavalInterdiction = 1;
            }
            else
            {
                if (numHits > ((Block)this.pieceMoved).CurrentStrength)
                    numStepLossesFromNavalInterdiction = (int)((Block)this.pieceMoved).CurrentStrength;
                else
                    numStepLossesFromNavalInterdiction = numHits;
            }

            return interceptionOccured;
        }

        public bool IsValidConnectionForAroundTheCapeStratMove(Edge<Region, Adjacency> edge, Region start)
        {
            if(MapInfo.IsLandRegion(edge.Start.RegionID) && MapInfo.IsLandRegion(edge.End.RegionID))
            {
                if(!(edge.Data is LandToLandAdjacency))
                    return false;

                if (((LandToLandAdjacency)edge.Data).ConnectionType == LandToLandAdjacency.LandConnectionType.AirConnection)
                {
                    if (!(this.pieceMoved is GroundSupportUnit))
                        return false;
                }

                if(!gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(edge.Start.RegionID)))
                    return false;
                if(!gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(edge.End.RegionID)))
                    return false;

                if(gameInfoProvider.GetRegionsAxisBlockList(edge.Start.RegionID).Count > 0)
                    return false;

                if(gameInfoProvider.GetRegionsAxisBlockList(edge.End.RegionID).Count > 0)
                    return false;
            }
            else if(edge.Data is SeaLandAdjacency)
            {
                MapInfo.RegionID landRegionID = MapInfo.IsSeaRegion(edge.Start.RegionID)? edge.End.RegionID : edge.Start.RegionID;
                MapInfo.RegionID seaRegionID = MapInfo.IsLandRegion(edge.Start.RegionID)? edge.End.RegionID : edge.Start.RegionID;
                if (seaRegionID != MapInfo.RegionID.AtlanticOcean && seaRegionID != MapInfo.RegionID.RedSea)
                    return false;
                LandRegion landRegion = (LandRegion)MapInfo.GetRegion(landRegionID);
                if (!((SeaLandAdjacency)edge.Data).Port)
                    return false;
                if (!gameInfoProvider.IsAlliedCountry(gameInfoProvider.GetRegionControl(landRegionID)))
                    return false;
                if (gameInfoProvider.GetRegionsAxisBlockList(landRegionID).Count > 0)
                    return false;
            }

            return true;
        }

        public bool AroundTheCapePossible(IGameStateInfoProvider gameInfoProvider)
        {
            this.gameInfoProvider = gameInfoProvider;
            if(this.Piece.CountryOwner == MapInfo.CountryID.GreatBritain)
            {
                int numTransportAvailable = 0;
                List<FleetPoint> fleetList = gameInfoProvider.GetFleetPointList(MapInfo.CountryID.GreatBritain, MapInfo.RegionID.AtlanticOcean);
                foreach (FleetPoint fleet in fleetList)
                {
                    if (!fleet.WithoutTransport)
                        numTransportAvailable++;
                }

                if(numTransportAvailable >= 4)
                {
                    if (MapInfo.PathExists(this.regionMovedFrom, MapInfo.RegionID.AtlanticOcean, IsValidConnectionForAroundTheCapeStratMove))
                    {
                        if (MapInfo.PathExists(this.regionMovedTo, MapInfo.RegionID.RedSea, IsValidConnectionForAroundTheCapeStratMove))
                            return true;
                    }
                    else if (MapInfo.PathExists(this.regionMovedFrom, MapInfo.RegionID.RedSea, IsValidConnectionForAroundTheCapeStratMove))
                    {
                        if (MapInfo.PathExists(this.regionMovedTo, MapInfo.RegionID.AtlanticOcean, IsValidConnectionForAroundTheCapeStratMove))
                            return true;
                    }
                }
            }

            return false;
        }

        public override bool IsLegal(IGameStateInfoProvider gameStateInfoProvider, ref string ruleString)
        {
            LandRegion fromLandRegionPotentialSwamp = (LandRegion)MapInfo.GetRegion(this.regionMovedFrom);

            if (fromLandRegionPotentialSwamp.Terrain == MapInfo.terrainType.swamp && this.breakThroughMove)
            {
                ruleString = "5.15 Swamp Terrain has the following effects:...b) Units in swamp areas may not use Breakthrough Movement Phases.";
                return false;
            }

            if (!IsLegalWithoutConsideringRoute(gameStateInfoProvider, ref ruleString))
                return false;

            if (!Move.IsWithinOperationLimits(gameStateInfoProvider, this.regionMovedFrom, this.regionMovedTo, this.pieceMoved, ref ruleString))
                return false;

            if(this.regionMovedTo == MapInfo.RegionID.Tobruk || this.regionMovedTo == MapInfo.RegionID.Sevastopol || this.regionMovedTo == MapInfo.RegionID.Leningrad || this.regionMovedTo == MapInfo.RegionID.Gibraltar || this.regionMovedTo == MapInfo.RegionID.Malta)
            {
                int numFriendlyBlocks = gameStateInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) ? gameStateInfoProvider.GetRegionsAxisBlockList(this.regionMovedTo).Count : gameStateInfoProvider.GetRegionsAlliedBlockList(regionMovedTo).Count;
                int numFriendlyGSUs = gameStateInfoProvider.IsAxisCountry(this.pieceMoved.CountryOwner) ? gameStateInfoProvider.GetRegionsAxisGSUList(this.regionMovedTo).Count : gameStateInfoProvider.GetRegionsAlliedGSUList(regionMovedTo).Count;
                if (this.pieceMoved is GroundSupportUnit)
                {
                    ruleString = "GSU's may not move to an fortress unless it is to launch an attack, see 5.5 Stacking Limits";
                    return false;
                }
                else
                {
                    LandRegion fortressRegion = (LandRegion)MapInfo.GetRegion(regionMovedTo);
                    if (numFriendlyBlocks >= (int)fortressRegion.Fortress)
                    {
                        ruleString = "The stacking limit for a fortress cannot be exceeded, see 5.5 Stacking Limits";
                        return false;
                    }
                }
            }

            if(aroundTheCape)
            {
                if (!AroundTheCapePossible(gameStateInfoProvider))
                    return false;
            }
            else
            {
                foreach (MapInfo.RegionID seaRegionPassedThrough in seaRegionsPassedThrough)
                {
                    if (seaRegionPassedThrough == MapInfo.RegionID.MediteraneanSea && this.pieceMoved is Block)
                    {
                        if (this.pieceMoved.CountryOwner == MapInfo.CountryID.Germany && gameStateInfoProvider.HasVichyBeenDeclared() && !gameStateInfoProvider.IsNationAtWar(MapInfo.CountryID.VichyFrance) && !gameStateInfoProvider.IsNationConquered(MapInfo.CountryID.VichyFrance) && gameInfoProvider.HasGermanUnitUsedItalianSeaTransportThisTurn())
                        {
                            ruleString = "9.12...Only one German ground unit may move using Italian Sea-transport per game-turn (Operational or Strategic Movement)";
                            return false;
                        }

                        int numItalianGroundUnits = 0;
                        int numGermanGroundUnits = 0;
                        System.Collections.IEnumerator EERegions = MapInfo.GetEuropeEngulfedRegions();
                        while (EERegions.MoveNext())
                        {
                            Region region = (Region)EERegions.Current;
                            if (MapInfo.IsInAfrica(region.RegionID))
                            {
                                foreach (Block block in gameInfoProvider.GetRegionsAxisBlockList(region.RegionID))
                                {
                                    if (block.CountryOwner == MapInfo.CountryID.Italy)
                                        numItalianGroundUnits++;
                                    else if (block.CountryOwner == MapInfo.CountryID.Germany)
                                        numGermanGroundUnits++;
                                }
                            }
                        }

                        if (numGermanGroundUnits >= numItalianGroundUnits)
                        {
                            ruleString = "9.12...No German ground unit may move into Africa via Sea-transport unless, at the instant the move is made, there are more Italian ground units than German ground units already in Africa.";
                            return false;
                        }
                    }
                }
            }

            return true;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode pieceMovedNode = xml.CreateElement("pieceMoved");
            System.Xml.XmlNode seaRegionsPassedThroughNode = xml.CreateElement("seaRegionsPassedThrough");
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("Move");
            System.Xml.XmlAttribute typeAttr = xml.CreateAttribute("Type");
            System.Xml.XmlAttribute regionMovedFromAttr = xml.CreateAttribute("regionMovedFrom");
            System.Xml.XmlAttribute regionMovedToAttr = xml.CreateAttribute("regionMovedTo");
            System.Xml.XmlAttribute numStepLossesFromNavalInterdictionAttr = xml.CreateAttribute("numStepLossesFromNavalInterdiction");
            System.Xml.XmlAttribute aroundTheCapeAttr = xml.CreateAttribute("aroundTheCape");
            System.Xml.XmlAttribute breakThroughMoveAttr = xml.CreateAttribute("breakThroughMove");
            System.Xml.XmlAttribute goesThroughWesternWeatherZoneAttr = xml.CreateAttribute("goesThroughWesternWeatherZone");
            System.Xml.XmlAttribute findRouteWithoutGoingThroughWesternWeatherZoneAttr = xml.CreateAttribute("findRouteWithoutGoingThroughWesternWeatherZone");
            System.Xml.XmlAttribute moveBlockedByOperationOverlordAttr = xml.CreateAttribute("moveBlockedByOperationOverlord");
            System.Xml.XmlAttribute numSeaRegionsAllowedAttr = xml.CreateAttribute("numSeaRegionsAllowed");

            nodeToReturn.AppendChild(gameTurn.Serialise(xml));
            typeAttr.Value = this.GetType().ToString();
            regionMovedFromAttr.Value = Enum.GetName(regionMovedFrom.GetType(), regionMovedFrom);
            regionMovedToAttr.Value = Enum.GetName(regionMovedTo.GetType(), regionMovedTo);
            numStepLossesFromNavalInterdictionAttr.Value = numStepLossesFromNavalInterdiction.ToString();
            aroundTheCapeAttr.Value = aroundTheCape.ToString();
            breakThroughMoveAttr.Value = breakThroughMove.ToString();
            goesThroughWesternWeatherZoneAttr.Value = goesThroughWesternWeatherZone.ToString();
            findRouteWithoutGoingThroughWesternWeatherZoneAttr.Value = findRouteWithoutGoingThroughWesternWeatherZone.ToString();
            moveBlockedByOperationOverlordAttr.Value = moveBlockedByOperationOverlord.ToString();
            numSeaRegionsAllowedAttr.Value = numSeaRegionsAllowed.ToString();

            nodeToReturn.Attributes.Append(typeAttr);
            nodeToReturn.Attributes.Append(regionMovedFromAttr);
            nodeToReturn.Attributes.Append(regionMovedToAttr);
            nodeToReturn.Attributes.Append(numStepLossesFromNavalInterdictionAttr);
            nodeToReturn.Attributes.Append(aroundTheCapeAttr);
            nodeToReturn.Attributes.Append(breakThroughMoveAttr);
            nodeToReturn.Attributes.Append(goesThroughWesternWeatherZoneAttr);
            nodeToReturn.Attributes.Append(findRouteWithoutGoingThroughWesternWeatherZoneAttr);
            nodeToReturn.Attributes.Append(moveBlockedByOperationOverlordAttr);
            nodeToReturn.Attributes.Append(numSeaRegionsAllowedAttr);
            if (this.pieceMoved is Block)
                pieceMovedNode.AppendChild(((Block)pieceMoved).Serialise(xml));
            else if (this.pieceMoved is GroundSupportUnit)
                pieceMovedNode.AppendChild(((GroundSupportUnit)pieceMoved).Serialise(xml));
            nodeToReturn.AppendChild(pieceMovedNode);

            foreach (MapInfo.RegionID seaRegionID in seaRegionsPassedThrough)
            {
                System.Xml.XmlNode seaRegionPassedThroughNode = xml.CreateElement("seaRegionPassedThrough");
                seaRegionPassedThroughNode.InnerText = Enum.GetName(seaRegionID.GetType(), seaRegionID);
                seaRegionsPassedThroughNode.AppendChild(seaRegionPassedThroughNode);
            }
            nodeToReturn.AppendChild(seaRegionsPassedThroughNode);

            return nodeToReturn;
        }

        public new static Move Deserialise(System.Xml.XmlNode node)
        {
            if (node.Attributes["Type"].Value == typeof(StrategicMove).ToString() && node.Name == "Move")
            {
                System.Xml.XmlNode seaRegionsPassedThroughNode = node.SelectSingleNode("seaRegionsPassedThrough");
                GameTurn parsedGameTurn = GameTurn.Deserialise(node.SelectSingleNode("GameTurn"));
                StrategicMove strategicMoveToReturn = new StrategicMove(parsedGameTurn.CurrentGameDate, parsedGameTurn.CurrentGamePhase, parsedGameTurn.CurrentGameSubPhase, (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["regionMovedFrom"].Value), (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["regionMovedTo"].Value), PlayingPiece.Deserialise(node.SelectSingleNode("pieceMoved")));

                foreach (System.Xml.XmlNode seaRegionPassedThroughNode in seaRegionsPassedThroughNode)
                {
                    strategicMoveToReturn.seaRegionsPassedThrough.Add((MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), seaRegionPassedThroughNode.InnerText));
                }
                strategicMoveToReturn.numStepLossesFromNavalInterdiction = int.Parse(node.Attributes["numStepLossesFromNavalInterdiction"].Value);
                strategicMoveToReturn.aroundTheCape = bool.Parse(node.Attributes["aroundTheCape"].Value);
                strategicMoveToReturn.breakThroughMove = bool.Parse(node.Attributes["breakThroughMove"].Value);
                strategicMoveToReturn.goesThroughWesternWeatherZone = bool.Parse(node.Attributes["goesThroughWesternWeatherZone"].Value);
                strategicMoveToReturn.findRouteWithoutGoingThroughWesternWeatherZone = bool.Parse(node.Attributes["goesThroughWesternWeatherZone"].Value);
                strategicMoveToReturn.moveBlockedByOperationOverlord = bool.Parse(node.Attributes["moveBlockedByOperationOverlord"].Value);
                strategicMoveToReturn.numSeaRegionsAllowed = int.Parse(node.Attributes["numSeaRegionsAllowed"].Value);

                return strategicMoveToReturn;
            }
            else
                throw new InvalidOperationException();
        }

        public override System.Windows.Forms.TreeNode GetMoveTreeNode(System.Windows.Forms.TreeView treeView)
        {
            if (!treeView.ImageList.Images.ContainsKey(pieceMoved.GetTreeViewImageListKey(true)))
            {
                if (pieceMoved is Block)
                {
                    Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                    Graphics g = Graphics.FromImage(b);
                    PlayingPieceGraphics.PaintBlockFace(g, (Block)pieceMoved, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), true);
                    treeView.ImageList.Images.Add(pieceMoved.GetTreeViewImageListKey(true), b);
                }
                else if (pieceMoved is GroundSupportUnit)
                {
                    Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                    Graphics g = Graphics.FromImage(b);
                    PlayingPieceGraphics.PaintGSUFace(g, (GroundSupportUnit)pieceMoved, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), true);
                    treeView.ImageList.Images.Add(pieceMoved.GetTreeViewImageListKey(true), b);
                }
            }
            return new System.Windows.Forms.TreeNode("Strat-move from " + MapInfo.GetRegionName(this.regionMovedFrom) + " to " + MapInfo.GetRegionName(this.regionMovedTo), treeView.ImageList.Images.IndexOfKey(pieceMoved.GetTreeViewImageListKey(true)), treeView.ImageList.Images.IndexOfKey(pieceMoved.GetTreeViewImageListKey(true)));
        }

        public override string GetStringForNetworkMessage()
        {
            string returnString;

            returnString = "Strategically Moved " + this.pieceMoved.GetHiddenStringDescription() + " from " + Enum.GetName(typeof(MapInfo.RegionID), this.regionMovedFrom) + " to " + Enum.GetName(typeof(MapInfo.RegionID), this.regionMovedTo);
            if (numStepLossesFromNavalInterdiction > 0)
                returnString += " with " + numStepLossesFromNavalInterdiction.ToString() + " step losses from naval interdiction";

            return returnString;
        }
    }
}
